iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 30
1
Software Development

服務開發雜談系列 第 30

微服務的12 Factor原則

  • 分享至 

  • xImage
  •  

12 Factor原則簡介

12Factor, 全名是The Twelve-Factor App, Heroku平台團隊彙整了這些實戰經驗並發表出來.

12 Factor能應用在微服務應用以及各種語言開發的應用上. 微服務應用的特徵是需要遵循一套設計規範.
在微服務下的開發者必須改變自己的開發習慣來滿足自動化容器化基礎設施管理等要求.
12 Factor就是定義出一套用於這規劃下的新型契約.
這12 Factor內容包含了

  1. Codebase
  2. Dependencies
  3. Config
  4. Backing services
  5. Build, release, run
  6. Processes
  7. Port biding
  8. Concurrency
  9. Disposability
  10. Dev/prod parity
  11. Logs
  12. Admin processes

    依序慢慢介紹

Codebase

基本定義: 一份基準代碼Codebase, 對上多份佈署Deploy.
意思就是微服務的codebase都是相同的一份, 雖然可能會佈署多個版本到不同環境(開發、測試、產線)上, 同時也以不同的介質(Docker、VM...)做部屬.
Codebase是以代碼的方式被統一集中在Version control system中(Git、Subversion...), 這樣就能透過Git來追蹤每一個佈署出去的微服務應用.

Dependencies

基本定義: 顯式聲明依賴關係

  • 對於每個微服務, 要聲明所有的依賴項目, 方便編譯工具能正確的編譯出微服務應用. 像是Java Maven的pom.xml, Go的go.mod, Node的package.json. 這是編譯過程的顯式聲明依賴關係.
  • 業務微服務之間應該也要明確定義相互的依賴關係, 可以透過一些服務編排框架來達成. 昨天提到的Jaeger DAG也有點這味道.

Config

基本定義: 在環境中儲存配置

  • 代碼內要避免跟環境有關連的hard code. 像是代碼內有 if env == staging xxx else if env == prod yyy
  • 微服務的開發跟交付分別對應兩個完全隔離的階段還有環境; 開發階段撰寫codebase, 交付階段負責管理環境變數. 這樣Git分支上, 就沒必要分一堆dev、test、prod, 哪天又多了staging、qa, 或者開發者自己的ithome-dev...這樣不同分支不同的config組合太複雜了.
  • 因此config不應該以file形式放到Git上, 應該直接放置在環境變量上, 像是evn上. 又或者使用K8S的configmaps 或是MicroProfile Config, Puppet, Vargrant等等的, 讓GIT和代碼與config撥離. Docker則是能透過-e(env)來設定環境變數.
docker run -e "DATABASE=mongodb://localhost:27017" -e "SECRET=ithome" myapp
  • 不然就是統一找config server要config, 之前介紹的etcd可以充當這角色. 每個環境獨立一組etcd server, 內部IP都一樣, 服務起來透過一樣的host:port來存取.

Backing services

基本定義: 把後端服務作為附加資源

  • 微服務鎖依賴的外部服務(需要透過網路調用的)都屬於依賴資源.

  • 微服務鎖依賴的資源都是可以被移植, 且可以鬆散地整合其他類似的資源. 舉例: 服務依賴於MySQL的接口, 開發實用到本地的MySQL, 產線則可以遷移到AWS RDS上, code都不需要更動.

  • 如果依賴的資源出現異常, 運維只需要卸載現在的MySQL, 並且掛載上新的MySQL實例, 最多也只需要動到config.

  • 微服務的內部組件, 不應該直接依賴資源, 而是應該依賴其接口; 也只需要關注自己內部的實現, 然後也只需要了解外部資源提供的接口, 不用詳細了解外部依賴資源的具體實現.

Build, release, run

基本定義: 嚴格分離Build, Release, Run

  • Build stage是微服務應用透過自動或手動方式, 把code編譯成微服務組件(exe, binary)
  • Release stage是把微服務組件發到對應的Registry(Docker-Registry, Harbor, Github release tag)上, 提供給外部運行環境來下載
  • Run stage把微服務組件從Registry拉下來+第三點的config env, 佈署到對應的運行環境上.
  • 盡可能透過CI/CD工具來自動化完成上面三個階段
  • 每一個發布的版本都應該要有唯一的版本發布ID

Processes

基本定義: 以一個或是多個無狀態進程運行微服務應用

  • DAY3有提到什麼是Stateless無狀態
  • 微服務組件在開發設計時, 應該考慮到隨時會失敗或是crash的情況來設計. 這種設計可以實現微服務進程隨時被建立或是被Kill, 尤其在Auto-Scale in/out階段.

Port biding

基本定義: 透過Port綁定來提供服務

  • 微服務組件透過Port來提供服務. 不同的Port綁定不同的請求協議(Http、rpc、redis、mysql...), 並監聽所有發送到該端口的請求.
  • 每個微服務組件應該透過服務發現機制(Day20提到)對外提供服務

Concurrency

基本定義: 服務透過Process模型進行水平擴展

  • 微服務應用本身只是一個process, 但業務分支可以內部開啟多個Thread/coroutine來分散prcess性能瓶頸.
  • 雷同餘上面的Prcess觀點, 同一個服務功能, 可以起對多個微服務實例(一個實例就是一個process), 達到水平擴展.
  • 透過添加無狀態process進行水平擴展, 也是上面提過的觀點.

Disposability

基本定義: 快速啟動、優雅終止, 可最大化系統可容忍干擾的能力(Robustness)

  • 微服務啟動時, 可以透過Lazy Loading的方式實現快速啟動.
  • 微服務終止時硬確保所有資源已經釋放(db連線...), 所有監聽也關閉(等待還沒完成的請求結束, 且不再接受新的請求), 然後優雅地關閉進程.
  • 當非正常結束時(crash), 微服務會自動恢復到默認狀態.
  • 服務熔斷跟降級的應用

Dev/Prod parity

基本定義: 環境等價, 盡可能保持dev、pre-release、prod環境相同

  • 保持微服務的dev、pre-release、prod盡可能相似, 這樣可以保證應用的高品質、持續交付跟佈署
  • 透過Docker來減少因環境不同帶來的排錯等成本溝通問題, 否則就要用Adapter來支持差異性
  • 對於後台資料, 差異性的存在是不可避免的, 像是報表資料, 開發環境就不是很多甚至沒有, 這時可能就要有一些機制來隔離
  • 最好開發&運維一體化, 同一批人, 減少溝通成本.

Logs

基本定義: 將Log視為Event streams(事件流)

  • 微服務應該建立統一的服務來管理日誌(ELK、Graylog、Cloudwatch...)
  • 每個運行的微服務都直接透過Stdout和Stderr來輸出日誌; 開發時期透過console來查看時間排序下的Event log; 上到環境後, 則是透過集中服務, 來收集、聚合、索引、分析這些Log
  • 採用分布式追蹤服務(Day29提到)來解決微服務之間調用的問題
  • 透過Log對微服務進行監控(Prometheus, Jaeger...)
  • 把Event stream透過Splunk做分析, 或是存放在Hadoop做儲存查找分析.

Admin processes

基本定義: 把維護/管理任務當作一次性process執行

  • 後台維護任務通常跟業務應用本身的技術框架還有作法不太一樣, 所以盡可能實現上是分離的.
  • 微服務管理或是系統的維護是應用維護的基礎部份, 要作為一次性prcess來執行; 像是db migration, db snapshot, schema/table更動, 定期renew憑證等等的.
  • 把這些一次性作業寫成腳本或是Shell, 當成一般程式來執行, 也進到Git做版控.
  • 也能把這些場景變成微服務模式來實現

部份內容參考小弟以前的文章


上一篇
Jaeger續, DAG套件與更多案例
下一篇
分庫分表 Sharding - 1
系列文
服務開發雜談33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言